import cv2
import numpy as np
import random
from collections import deque
# 提高帧率
# 游戏参数
width, height = 800, 600  # 地图范围
snake_size = 10  # 蛇身和食物的大小
fps = 1000  # 移动速度

# 初始化游戏状态
snake = [(100, 100), (90, 100), (80, 100)]  # 初始蛇身位置
direction = 'RIGHT'
food = (random.randint(0, width // snake_size - 1) * snake_size,
        random.randint(0, height // snake_size - 1) * snake_size)

def draw_snake_and_food(frame):
    # 绘制蛇的身体
    for i, (x, y) in enumerate(snake):
        color = (0, 255, 0) if i > 0 else (255, 0, 0)  # 蛇的身体用绿色，头部用蓝色
        cv2.rectangle(frame, (x, y), (x + snake_size, y + snake_size), color, -1)
    
    # 绘制食物
    cv2.rectangle(frame, (food[0], food[1]), (food[0] + snake_size, food[1] + snake_size), (0, 0, 255), -1)

def move_snake(new_head):
    global food
    if new_head == food:
        snake.insert(0, new_head)
        food = (random.randint(0, width // snake_size - 1) * snake_size,
                random.randint(0, height // snake_size - 1) * snake_size)
    else:
        snake.insert(0, new_head)
        snake.pop()

def check_collision(new_head):
    x, y = new_head
    if x < 0 or x >= width or y < 0 or y >= height or new_head in snake:
        return True
    return False

def bfs(start, target):
    queue = deque([(start, [])])
    visited = set([start])

    while queue:
        (x, y), path = queue.popleft()
        if (x, y) == target:
            return path

        for dx, dy, d in [(-snake_size, 0, 'LEFT'), (snake_size, 0, 'RIGHT'), (0, -snake_size, 'UP'), (0, snake_size, 'DOWN')]:
            next_pos = (x + dx, y + dy)
            if 0 <= next_pos[0] < width and 0 <= next_pos[1] < height and next_pos not in visited and next_pos not in snake:
                queue.append((next_pos, path + [next_pos]))
                visited.add(next_pos)
    return None

def draw_path(frame, path):
    if path:
        for point in path:
            # 绘制灰色实线框，大小与蛇头一致
            cv2.rectangle(frame, (point[0], point[1]), (point[0] + snake_size, point[1] + snake_size), (128, 128, 128), 1)

def show_message(message, font_scale=1, thickness=2, wait_key=True):
    frame = np.zeros((height, width, 3), dtype=np.uint8)
    text_size = cv2.getTextSize(message, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness)[0]
    text_x = (width - text_size[0]) // 2
    text_y = (height + text_size[1]) // 2
    cv2.putText(frame, message, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255, 255, 255), thickness)
    cv2.imshow('Snake Game', frame)
    if wait_key:
        cv2.waitKey(0)

# 显示“按任意键开始”
show_message("Press any key to start the game...", font_scale=0.8, thickness=2)

# 主循环
game_over = False
last_frame = None  # 用于保存最后一帧的画面
while not game_over:
    # 创建空白画布
    frame = np.zeros((height, width, 3), dtype=np.uint8)

    # 绘制蛇和食物
    draw_snake_and_food(frame)

    # 计算最短路径
    path = bfs(snake[0], food)
    if path is None:
        game_over = True
        show_message("Game Over! Press any key to exit...", font_scale=0.8, thickness=2, wait_key=True)
        last_frame = frame.copy()  # 保存最后一帧的画面
        break

    # 绘制路径
    draw_path(frame, path)

    # 计算新头部位置
    if path:
        new_head = path[0]
    else:
        new_head = snake[0]

    # 检查碰撞
    if check_collision(new_head):
        game_over = True
        show_message("Game Over! Press any key to exit...", font_scale=0.8, thickness=2, wait_key=True)
        last_frame = frame.copy()  # 保存最后一帧的画面
        break

    # 移动蛇
    move_snake(new_head)

    # 显示目标点的坐标和当前的蛇身长度
    food_text = f"Food: ({food[0]}, {food[1]})"
    length_text = f"Length: {len(snake)}"
    cv2.putText(frame, food_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
    cv2.putText(frame, length_text, (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)

    # 显示帧
    cv2.imshow('Snake Game', frame)

    # 处理键盘输入
    key = cv2.waitKey(int(1000 / fps)) & 0xFF
    if key == ord('q'):
        break

# 保存最后一帧的画面
if last_frame is not None:
    cv2.imwrite('last_frame.png', last_frame)

# 等待按键释放所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()